package service

import (
	"strconv"
	"strings"
	"trpg-base/dto"
	"trpg-base/entity"
	"trpg-common/constants"
	common_dto "trpg-common/dto"
	"trpg-common/logger"
	"trpg-common/utils/collection_util"
	"trpg-common/utils/gorm_util"
	"trpg-common/utils/oss_util"
	"trpg-common/utils/snowflake_util"
	"trpg-common/utils/time_util"

	"github.com/pkg/errors"
)

const contentPicPath = "/content/pics/"

type ForumService struct{}

func (s ForumService) SearchTopic(request dto.ForumTopicRequest, page gorm_util.PageRequest, user common_dto.UserInfo) *gorm_util.PageResult {
	paramBuilder := gorm_util.NewParamBuilder().Model(&entity.ForumTopic{}).Eq("is_deleted", constants.DeleteNo)
	if request.Search != "" {
		paramBuilder.Like("topic", request.Search)
	}
	if request.Created {
		paramBuilder.Eq("creator", user.Uid)
	} else if request.Collected {
		collections := make([]entity.ForumTopicLikeCollection, 0)
		gorm_util.SelectByParamBuilder(gorm_util.NewParamBuilder().Model(&entity.ForumTopicLikeCollection{}).Eq("uid", user.Uid).Eq("type", 1).Eq("is_deleted", constants.DeleteNo), &collections)
		collectionIds := make([]int64, 0, len(collections))
		for _, collection := range collections {
			collectionIds = append(collectionIds, collection.TopicId)
		}
		paramBuilder.In("id", collectionIds)
	}
	if request.BeginTime != nil {
		paramBuilder.Gte("gmt_created", request.BeginTime)
	}
	if request.EndTime != nil {
		paramBuilder.Lte("gmt_created", request.EndTime)
	}
	switch request.Order {
	case "gmtCreated":
		paramBuilder.Order("gmt_created", request.OrderType)
	case "likeCount":
		paramBuilder.Order("like_count", request.OrderType)
	case "collectCount":
		paramBuilder.Order("collect_count", request.OrderType)
	}
	res := make([]entity.ForumTopic, 0)
	result := gorm_util.PageSelectByParamBuilder(paramBuilder, &res, page)
	creators := make([]string, 0, len(res))
	for _, topic := range res {
		creators = append(creators, topic.Creator)
	}
	idNameMap := userService.GetUserIdNameMapByUidList(creators)
	// 查询查询者点赞和收藏的帖子
	likeSet, collectionSet := s.GetLikeAndCollectionTopicsByUser(user.Uid)
	for i, _ := range res {
		if res[i].Creator == user.Uid {
			res[i].IsCreator = true
		}
		if likeSet.Contains(res[i].Id) {
			res[i].IsLiked = true
		}
		if collectionSet.Contains(res[i].Id) {
			res[i].IsCollected = true
		}
		res[i].CreatorName = idNameMap[res[i].Creator]
	}
	result.List = res
	return result
}

func (ForumService) NewTopic(topic entity.ForumTopic, user common_dto.UserInfo) {
	gorm_util.Transaction(func() {
		topic.Creator = user.Uid
		topic.Modifier = user.Uid
		topic.GmtCreated = time_util.Now()
		topic.GmtModified = time_util.Now()
		gorm_util.InsertUpdateOne(&topic)
		content := entity.ForumContent{}
		content.Creator = user.Uid
		content.Modifier = user.Uid
		content.GmtCreated = time_util.Now()
		content.GmtModified = time_util.Now()
		content.TopicId = topic.Id
		content.Content = topic.Content
		if topic.PicFiles != nil && len(topic.PicFiles) != 0 {
			for _, file := range topic.PicFiles {
				split := strings.Split(file.Filename, ".")
				suffix := split[len(split)-1]
				path := contentPicPath + strconv.FormatInt(snowflake_util.SnowFlakeID(), 10) + "." + suffix
				content.PicsStr += path + ","
				oss_util.UploadMultiFile(file, path)
			}
		}
		gorm_util.InsertUpdateOne(&content)
	})
}

func (ForumService) LockTopic(topicId int64, user common_dto.UserInfo) {
	topic := entity.ForumTopic{}
	topic.Id = topicId
	topic.IsDeleted = constants.DeleteNo
	gorm_util.SelectOneByCondition(&topic)
	if topic.Creator != user.Uid {
		logger.Logger.Panicf("%v", errors.New("不是帖子创建人，无权操作！"))
	}
	topic.IsLocked = constants.DeleteYes
	topic.Modifier = user.Uid
	topic.GmtModified = time_util.Now()
	gorm_util.UpdateOneByCondition(&topic)
}

func (ForumService) UnlockTopic(topicId int64, user common_dto.UserInfo) {
	topic := entity.ForumTopic{}
	topic.Id = topicId
	topic.IsDeleted = constants.DeleteNo
	gorm_util.SelectOneByCondition(&topic)
	if topic.Creator != user.Uid {
		logger.Logger.Panicf("%v", errors.New("不是帖子创建人，无权操作！"))
	}
	topic.IsLocked = constants.DeleteNo
	topic.Modifier = user.Uid
	topic.GmtModified = time_util.Now()
	gorm_util.UpdateOneByCondition(&topic)
}

func (ForumService) DeleteTopic(topicId int64, user common_dto.UserInfo) {
	topic := entity.ForumTopic{}
	topic.Id = topicId
	topic.IsDeleted = constants.DeleteNo
	gorm_util.SelectOneByCondition(&topic)
	if topic.Creator != user.Uid {
		logger.Logger.Panicf("%v", errors.New("不是帖子创建人，无权操作！"))
	}
	topic.IsDeleted = constants.DeleteYes
	topic.Modifier = user.Uid
	topic.GmtModified = time_util.Now()
	gorm_util.UpdateOneByCondition(&topic)
}

func (ForumService) LikeTopic(topicId int64, user common_dto.UserInfo) {
	topic := entity.ForumTopic{}
	topic.Id = topicId
	gorm_util.SelectOneByCondition(&topic)
	topic.LikeCount += 1
	gorm_util.UpdateOneByCondition(&topic)
	likeCollection := entity.ForumTopicLikeCollection{}
	likeCollection.TopicId = topicId
	likeCollection.Uid = user.Uid
	likeCollection.Type = 0
	likeCollection.Creator = user.Uid
	likeCollection.Modifier = user.Uid
	likeCollection.GmtCreated = time_util.Now()
	likeCollection.GmtModified = time_util.Now()
	gorm_util.InsertUpdateOne(&likeCollection)
}

func (ForumService) DislikeTopic(topicId int64, user common_dto.UserInfo) {
	topic := entity.ForumTopic{}
	topic.Id = topicId
	gorm_util.SelectOneByCondition(&topic)
	topic.LikeCount -= 1
	if topic.LikeCount == 0 {
		gorm_util.UpdateBatchByParamBuilderAndMap(gorm_util.NewParamBuilder().Model(&entity.ForumTopic{}).Eq("id", topicId),
			map[string]interface{}{"like_count": 0})
	} else {
		gorm_util.UpdateOneByCondition(&topic)
	}
	gorm_util.UpdateBatchByParamBuilderAndMap(
		gorm_util.NewParamBuilder().Model(&entity.ForumTopicLikeCollection{}).Eq("topic_id", topicId).Eq("uid", user.Uid).Eq("type", 0).Eq("is_deleted", constants.DeleteNo),
		map[string]interface{}{"is_deleted": constants.DeleteYes})
}

func (ForumService) CollectTopic(topicId int64, user common_dto.UserInfo) {
	topic := entity.ForumTopic{}
	topic.Id = topicId
	gorm_util.SelectOneByCondition(&topic)
	topic.CollectCount += 1
	gorm_util.UpdateOneByCondition(&topic)
	likeCollection := entity.ForumTopicLikeCollection{}
	likeCollection.TopicId = topicId
	likeCollection.Uid = user.Uid
	likeCollection.Type = 1
	likeCollection.Creator = user.Uid
	likeCollection.Modifier = user.Uid
	likeCollection.GmtCreated = time_util.Now()
	likeCollection.GmtModified = time_util.Now()
	gorm_util.InsertUpdateOne(&likeCollection)
}

func (ForumService) CancelCollectTopic(topicId int64, user common_dto.UserInfo) {
	topic := entity.ForumTopic{}
	topic.Id = topicId
	gorm_util.SelectOneByCondition(&topic)
	topic.CollectCount -= 1
	if topic.CollectCount == 0 {
		gorm_util.UpdateBatchByParamBuilderAndMap(gorm_util.NewParamBuilder().Model(&entity.ForumTopic{}).Eq("id", topicId),
			map[string]interface{}{"collect_count": 0})
	} else {
		gorm_util.UpdateOneByCondition(&topic)
	}
	gorm_util.UpdateBatchByParamBuilderAndMap(
		gorm_util.NewParamBuilder().Model(&entity.ForumTopicLikeCollection{}).Eq("topic_id", topicId).Eq("uid", user.Uid).Eq("type", 1).Eq("is_deleted", constants.DeleteNo),
		map[string]interface{}{"is_deleted": constants.DeleteYes})
}

func (ForumService) Reply(reply entity.ForumReply, user common_dto.UserInfo) {
	reply.Creator = user.Uid
	reply.Modifier = user.Uid
	reply.GmtCreated = time_util.Now()
	reply.GmtModified = time_util.Now()
	gorm_util.InsertUpdateOne(&reply)
}

func (ForumService) GetLikeAndCollectionTopicsByUser(uid string) (likeSet *collection_util.Set[int64], collectionSet *collection_util.Set[int64]) {
	likeSet = collection_util.NewSet[int64]()
	collectionSet = collection_util.NewSet[int64]()
	likeCollections := make([]entity.ForumTopicLikeCollection, 0)
	gorm_util.SelectByParamBuilder(gorm_util.NewParamBuilder().Model(&entity.ForumTopicLikeCollection{}).Eq("uid", uid).Eq("is_deleted", constants.DeleteNo), &likeCollections)
	for _, likeCollection := range likeCollections {
		if likeCollection.Type == 0 {
			likeSet.Add(likeCollection.TopicId)
		} else if likeCollection.Type == 1 {
			collectionSet.Add(likeCollection.TopicId)
		}
	}
	return likeSet, collectionSet
}

func (s ForumService) SearchContent(request dto.ForumContentRequest, page gorm_util.PageRequest, user common_dto.UserInfo) *gorm_util.PageResult {
	paramBuilder := gorm_util.NewParamBuilder().Model(&entity.ForumContent{}).Eq("is_deleted", constants.DeleteNo).Eq("topic_id", request.TopicId)
	if request.Search != "" {
		paramBuilder.Like("content", `%`+request.Search+`%`)
	}
	if request.BeginTime != nil {
		paramBuilder.Gte("gmt_created", request.BeginTime)
	}
	if request.EndTime != nil {
		paramBuilder.Lte("gmt_created", request.EndTime)
	}
	switch request.Order {
	case "gmtCreated":
		paramBuilder.Order("gmt_created", request.OrderType)
	case "likeCount":
		paramBuilder.Order("like_count", request.OrderType)
	}
	res := make([]entity.ForumContent, 0)
	result := gorm_util.PageSelectByParamBuilder(paramBuilder, &res, page)
	creators := make([]string, 0, len(res))
	for _, topic := range res {
		creators = append(creators, topic.Creator)
	}
	userMap := userService.GetUserMapByUidList(creators)
	// 查询查询者点赞和收藏的帖子
	likeSet := s.GetLikeContentsByUser(user.Uid)
	for i, _ := range res {
		if res[i].Creator == user.Uid {
			res[i].IsCreator = true
		}
		if likeSet.Contains(res[i].Id) {
			res[i].IsLiked = true
		}
		res[i].CreatorName = userMap[res[i].Creator].Username
		res[i].CreatorAvatar = userMap[res[i].Creator].Avatar
		pics := strings.Split(res[i].PicsStr, ",")
		if len(pics) != 0 {
			res[i].Pics = make([]string, 0, len(pics))
			for _, pic := range pics {
				if pic != "" {
					res[i].Pics = append(res[i].Pics, oss_util.GetUrlByKey(pic))
				}
			}
		}
	}
	result.List = res
	return result
}

func (ForumService) GetLikeContentsByUser(uid string) *collection_util.Set[int64] {
	likeSet := collection_util.NewSet[int64]()
	likeCollections := make([]entity.ForumContentLike, 0)
	gorm_util.SelectByParamBuilder(gorm_util.NewParamBuilder().Model(&entity.ForumContentLike{}).Eq("uid", uid).Eq("is_deleted", constants.DeleteNo), &likeCollections)
	for _, likeCollection := range likeCollections {
		likeSet.Add(likeCollection.ContentId)
	}
	return likeSet
}

func (ForumService) NewContent(content entity.ForumContent, user common_dto.UserInfo) {
	content.Creator = user.Uid
	content.Modifier = user.Uid
	content.GmtCreated = time_util.Now()
	content.GmtModified = time_util.Now()
	if content.PicFiles != nil && len(content.PicFiles) != 0 {
		for _, file := range content.PicFiles {
			split := strings.Split(file.Filename, ".")
			suffix := split[len(split)-1]
			path := contentPicPath + strconv.FormatInt(snowflake_util.SnowFlakeID(), 10) + "." + suffix
			content.PicsStr += path + ","
			oss_util.UploadMultiFile(file, path)
		}
	}
	gorm_util.InsertUpdateOne(&content)
}

func (ForumService) LikeContent(contentId int64, user common_dto.UserInfo) {
	content := entity.ForumContent{}
	content.Id = contentId
	gorm_util.SelectOneByCondition(&content)
	content.LikeCount += 1
	gorm_util.UpdateOneByCondition(&content)
	likeCollection := entity.ForumContentLike{}
	likeCollection.ContentId = contentId
	likeCollection.Uid = user.Uid
	likeCollection.Creator = user.Uid
	likeCollection.Modifier = user.Uid
	likeCollection.GmtCreated = time_util.Now()
	likeCollection.GmtModified = time_util.Now()
	gorm_util.InsertUpdateOne(&likeCollection)
}

func (ForumService) DislikeContent(contentId int64, user common_dto.UserInfo) {
	content := entity.ForumContent{}
	content.Id = contentId
	gorm_util.SelectOneByCondition(&content)
	content.LikeCount -= 1
	if content.LikeCount == 0 {
		gorm_util.UpdateBatchByParamBuilderAndMap(gorm_util.NewParamBuilder().Model(&entity.ForumContent{}).Eq("id", contentId),
			map[string]interface{}{"like_count": 0})
	} else {
		gorm_util.UpdateOneByCondition(&content)
	}
	gorm_util.UpdateBatchByParamBuilderAndMap(
		gorm_util.NewParamBuilder().Model(&entity.ForumContentLike{}).Eq("content_id", contentId).Eq("uid", user.Uid).Eq("is_deleted", constants.DeleteNo),
		map[string]interface{}{"is_deleted": constants.DeleteYes})
}

func (ForumService) NewReply(reply entity.ForumReply, user common_dto.UserInfo) {
	reply.Creator = user.Uid
	reply.Modifier = user.Uid
	reply.GmtCreated = time_util.Now()
	reply.GmtModified = time_util.Now()
	gorm_util.InsertUpdateOne(&reply)
}

func (ForumService) SearchReplyList(contentId int64, request gorm_util.PageRequest) *gorm_util.PageResult {
	res := make([]entity.ForumReply, 0)
	pageResult := gorm_util.PageSelectByParamBuilder(gorm_util.NewParamBuilder().Model(&entity.ForumReply{}).Eq("content_id", contentId).Eq("is_deleted", constants.DeleteNo).OrderByDesc("gmt_created"),
		&res, request)
	userSet := collection_util.NewSet[string]()
	for _, reply := range res {
		userSet.Add(reply.Creator)
		if reply.ReplyUser != "" {
			userSet.Add(reply.ReplyUser)
		}
	}
	userIds := userSet.ToSlice()
	userMap := userService.GetUserMapByUidList(userIds)
	for i, _ := range res {
		res[i].CreatorName = userMap[res[i].Creator].Username
		res[i].CreatorAvatar = userMap[res[i].Creator].Avatar
		res[i].ReplyUserName = userMap[res[i].ReplyUser].Username
	}
	pageResult.List = res
	return pageResult
}
